//+------------------------------------------------------------------+
//|                                                     ListView.mqh |
//|                             Copyright 2000-2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "WndClient.h"                          // 客户区窗口基类（提供控件容器能力）
#include "Edit.h"                               // 编辑框控件类（列表行使用编辑框实现）
#include <Arrays/ArrayString.h>                 // 字符串数组类（存储列表文本数据）
#include <Arrays/ArrayLong.h>                   // 长整数数组类（存储列表值数据）

//+------------------------------------------------------------------+
//| CListView 类：MQL5 列表视图控件类                                 |
//| 核心能力：封装可滚动的列表控件，支持多行文本+值数据展示，提供       |
//|           增删改查、行选择、滚动控制等功能，基于编辑框实现列表行     |
//| 适用场景：数据列表展示（如订单列表、日志记录、参数选项等）           |
//+------------------------------------------------------------------+
class CListView : public CWndClient
  {
private:
   // 子控件与布局参数（私有，仅内部管理）
   CEdit             m_rows[];              // 列表行数组（每个行是一个只读编辑框）
   int               m_offset;              // 可见区域起始行索引（滚动偏移量）
   int               m_total_view;          // 可见行数（当前可显示的最大行数）
   int               m_item_height;         // 单行高度（像素，固定值）
   bool              m_height_variable;     // 高度自适应标志：true=随行数动态调整高度，false=固定高度

   // 数据存储（私有，确保数据安全）
   CArrayString      m_strings;             // 列表文本数据数组（每行显示的文本）
   CArrayLong        m_values;              // 列表值数据数组（每行关联的长整数参数）
   int               m_current;             // 当前选中行索引（CONTROLS_INVALID_INDEX 表示无选中）

public:
   //----------------------------------------------------------------
   // 构造与析构函数
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化列表视图默认状态
    * @details 初始化滚动偏移量为 0、可见行数为 0、单行高度为系统默认（CONTROLS_LIST_ITEM_HEIGHT），
    *          当前选中行为无效值，高度自适应标志为 false
    */
                     CListView(void);

   /**
    * @brief 析构函数：清理列表视图资源
    * @details 释放子控件数组、数据数组，依赖父类 CWndClient 析构逻辑清理容器资源
    */
                    ~CListView(void);

   //----------------------------------------------------------------
   // 控件创建与销毁：初始化列表并添加到图表
   //----------------------------------------------------------------
   /**
    * @brief 在指定图表位置创建列表视图控件
    * @param chart [in] 目标图表ID（0 表示当前活跃图表）
    * @param name [in] 控件唯一标识名（图表内不可重复）
    * @param subwin [in] 绑定的子窗口编号（0 = 主窗口，≥1 = 指标子窗口）
    * @param x1 [in] 左上角X坐标（像素，相对于图表窗口）
    * @param y1 [in] 左上角Y坐标（像素）
    * @param x2 [in] 右下角X坐标（像素）
    * @param y2 [in] 右下角Y坐标（像素，高度自适应时可能被调整）
    * @return bool - 创建结果：true=成功（父类初始化+子控件行创建完成），false=失败
    * @note 1. 自动计算可见行数（基于高度和单行高度）；
    *       2. 创建指定数量的列表行（编辑框）并初始化样式
    */
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);

   /**
    * @brief 销毁列表视图控件
    * @param reason [in] 销毁原因（默认 0，预留参数）
    * @details 清理子控件数组、数据数组，调用父类销毁方法释放容器资源
    */
   virtual void      Destroy(const int reason=0);

   //----------------------------------------------------------------
   // 事件处理：响应图表与用户交互事件
   //----------------------------------------------------------------
   /**
    * @brief 处理列表视图相关事件（如行点击、滚动等）
    * @param id [in] 事件ID（如 ON_CLICK、ON_SCROLL 等）
    * @param lparam [in] 长整数参数（事件相关数据，如行索引）
    * @param dparam [in] 双精度参数（事件相关数据）
    * @param sparam [in] 字符串参数（通常为控件名称，用于识别事件来源）
    * @return bool - 处理结果：true=事件已处理，false=未处理（交由父类处理）
    */
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

   //----------------------------------------------------------------
   // 布局配置：设置可见行数
   //----------------------------------------------------------------
   /**
    * @brief 设置列表的可见行数（仅在未创建控件时有效）
    * @param value [in] 目标可见行数（≥1）
    * @return bool - 设置结果：true=成功（仅首次调用有效），false=失败（控件已创建或参数无效）
    * @note 控件创建后不可修改可见行数，需通过高度自适应或滚动条控制显示范围
    */
   bool              TotalView(const int value);

   //----------------------------------------------------------------
   // 数据填充：添加列表项（兼容旧版本接口）
   //----------------------------------------------------------------
   /**
    * @brief 添加列表项（文本+值），兼容旧版本接口
    * @param item [in] 列表项文本（将显示在新行）
    * @param value [in] 列表项关联值（默认 0，若为 0 则自动赋值为当前数据总数）
    * @return bool - 添加结果：true=成功，false=失败
    * @note 实际调用 ItemAdd() 实现，仅为兼容旧代码保留
    */
   virtual bool      AddItem(const string item,const long value=0);

   //----------------------------------------------------------------
   // 数据管理：增删改查列表项
   //----------------------------------------------------------------
   /**
    * @brief 添加列表项（文本+值）到列表末尾
    * @param item [in] 列表项文本（显示内容）
    * @param value [in] 列表项关联值（自定义参数，如ID、状态等）
    * @return bool - 添加结果：true=成功（数据数组更新+视图刷新），false=失败
    * @note 当行数超过可见行数时，自动启用垂直滚动条
    */
   virtual bool      ItemAdd(const string item,const long value=0);

   /**
    * @brief 在指定索引处插入列表项（文本+值）
    * @param index [in] 插入位置索引（0 表示首行，≥数据总数表示插入到末尾）
    * @param item [in] 列表项文本（显示内容）
    * @param value [in] 列表项关联值（自定义参数）
    * @return bool - 插入结果：true=成功（数据数组更新+视图刷新），false=失败
    */
   virtual bool      ItemInsert(const int index,const string item,const long value=0);

   /**
    * @brief 更新指定索引处的列表项（文本+值）
    * @param index [in] 待更新项索引（需在 0~数据总数-1 范围内）
    * @param item [in] 新的列表项文本
    * @param value [in] 新的列表项关联值
    * @return bool - 更新结果：true=成功（数据数组更新+视图刷新），false=失败
    */
   virtual bool      ItemUpdate(const int index,const string item,const long value=0);

   /**
    * @brief 删除指定索引处的列表项
    * @param index [in] 待删除项索引（需在 0~数据总数-1 范围内）
    * @return bool - 删除结果：true=成功（数据数组更新+视图刷新），false=失败
    * @note 当行数少于可见行数时，自动隐藏垂直滚动条
    */
   virtual bool      ItemDelete(const int index);

   /**
    * @brief 清空所有列表项
    * @return bool - 清空结果：true=成功（数据数组清空+视图刷新+滚动条隐藏），false=失败
    */
   virtual bool      ItemsClear(void);

   //----------------------------------------------------------------
   // 选中行操作：获取/设置当前选中行
   //----------------------------------------------------------------
   /**
    * @brief 获取当前选中行的索引
    * @return int - 选中行索引（CONTROLS_INVALID_INDEX 表示无选中行）
    */
   int               Current(void);

   /**
    * @brief 获取当前选中行的文本
    * @return string - 选中行文本（无选中行时返回空字符串）
    */
   string            Select(void);

   /**
    * @brief 通过索引设置当前选中行
    * @param index [in] 目标选中行索引（0~数据总数-1，CONTROLS_INVALID_INDEX 表示取消选中）
    * @return bool - 设置结果：true=成功（选中状态更新+视图刷新），false=失败
    * @note 若目标行不可见，自动滚动视图使其可见
    */
   bool              Select(const int index);

   /**
    * @brief 通过文本内容设置当前选中行
    * @param text [in] 目标文本（精确匹配）
    * @return bool - 设置结果：true=成功（找到匹配文本并选中），false=失败（未找到文本）
    */
   bool              SelectByText(const string text);

   /**
    * @brief 通过关联值设置当前选中行
    * @param value [in] 目标关联值（精确匹配）
    * @return bool - 设置结果：true=成功（找到匹配值并选中），false=失败（未找到值）
    */
   bool              SelectByValue(const long value);

   //----------------------------------------------------------------
   // 数据读取：获取当前选中行的关联值
   //----------------------------------------------------------------
   /**
    * @brief 获取当前选中行的关联值
    * @return long - 选中行关联值（无选中行时返回 0）
    */
   long              Value(void);

   //----------------------------------------------------------------
   // 控件状态：设置控件可见性
   //----------------------------------------------------------------
   /**
    * @brief 设置列表视图为可见状态
    * @return bool - 设置结果：true=成功（父类可见性设置+行控件显示调整），false=失败
    * @note 高度自适应时，根据当前行数调整控件高度并显示对应行
    */
   virtual bool      Show(void);

protected:
   //----------------------------------------------------------------
   // 内部子控件创建：创建单个列表行（保护，仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 创建指定索引的列表行（编辑框控件）
    * @param index [in] 行索引（对应 m_rows 数组下标）
    * @return bool - 创建结果：true=成功（编辑框初始化+添加到容器），false=失败
    * @note 初始化行的位置、尺寸、样式（只读、默认颜色等）
    */
   bool              CreateRow(const int index);

   //----------------------------------------------------------------
   // 容器事件回调：处理控件尺寸变化（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 控件尺寸变化事件回调
    * @return bool - 处理结果：true=成功（父类尺寸调整+行尺寸与滚动条位置更新），false=失败
    */
   virtual bool      OnResize(void);

   //----------------------------------------------------------------
   // 滚动事件回调：处理滚动条显示/隐藏与滚动操作（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 垂直滚动条显示事件回调
    * @return bool - 处理结果：true=成功（调整行宽度以适配滚动条），false=失败
    */
   virtual bool      OnVScrollShow(void);

   /**
    * @brief 垂直滚动条隐藏事件回调
    * @return bool - 处理结果：true=成功（恢复行宽度），false=失败
    */
   virtual bool      OnVScrollHide(void);

   /**
    * @brief 向上滚动一行事件回调
    * @return bool - 处理结果：true=成功（更新滚动偏移量+视图刷新），false=失败
    */
   virtual bool      OnScrollLineUp(void);

   /**
    * @brief 向下滚动一行事件回调
    * @return bool - 处理结果：true=成功（更新滚动偏移量+视图刷新），false=失败
    */
   virtual bool      OnScrollLineDown(void);

   //----------------------------------------------------------------
   // 行交互事件回调：处理行点击（保护，仅子类可重写）
   //----------------------------------------------------------------
   /**
    * @brief 列表行点击事件回调
    * @param index [in] 被点击行的索引（相对于可见区域，非数据数组索引）
    * @return bool - 处理结果：true=成功（更新选中行+发送 ON_CHANGE 事件），false=失败
    */
   virtual bool      OnItemClick(const int index);

   //----------------------------------------------------------------
   // 视图刷新：更新列表显示内容（保护，仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 刷新列表视图（同步数据数组与行控件显示）
    * @return bool - 刷新结果：true=成功（所有可见行文本与选中状态更新），false=失败
    */
   bool              Redraw(void);

   /**
    * @brief 设置指定行的选中状态（颜色变化）
    * @param index [in] 行索引（相对于可见区域，非数据数组索引）
    * @param select [in] 选中状态：true=选中（高亮），false=未选中（默认样式）
    * @return bool - 设置结果：true=成功（行颜色更新），false=失败
    */
   bool              RowState(const int index,const bool select);

   /**
    * @brief 检查并确保当前选中行可见（自动滚动）
    * @return bool - 处理结果：true=成功（选中行已可见或滚动后可见），false=失败
    */
   bool              CheckView(void);
  };

//+------------------------------------------------------------------+
//| CListView 事件映射：关联子控件事件到处理函数（用于IDE智能提示）     |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CListView)
   ON_INDEXED_EVENT(ON_CLICK, m_rows, OnItemClick)  // 列表行点击事件 → 调用 OnItemClick（带行索引）
EVENT_MAP_END(CWndClient)
//+------------------------------------------------------------------+